/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bgu.sonar.util.collections;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

/**
 *
 * @author bennyl
 */
public class RangeOfNumbersList implements List<Integer> {

    int start, end, steps;

    public RangeOfNumbersList(int start, int end, int steps) {
        this.start = start;
        this.end = end;
        this.steps = steps;
    }

    @Override
    public int size() {
        return (int) Math.floor((double) (end - start) / (double) steps) + 1;
    }

    @Override
    public boolean isEmpty() {
        return size() == 0;
    }

    @Override
    public boolean contains(Object o) {
        if (o instanceof Number) {
            int v = ((Number) o).intValue();
            return v >= start && v <= end && start % steps == v % steps;
        }

        return false;
    }

    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            int current = start - steps;

            @Override
            public boolean hasNext() {
                return current + steps <= end;
            }

            @Override
            public Integer next() {
                if (hasNext()) {
                    return current += steps;
                }

                return null;
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
            }
        };
    }

    @Override
    public Integer[] toArray() {
        Integer[] result = new Integer[size()];
        int pos = 0;
        for (int i = start; i <= end; i += steps) {
            result[pos++] = i;
        }
        return result;
    }

    @Override
    public <T> T[] toArray(T[] a) {
        return (T[]) toArray();
    }

    @Override
    public boolean add(Integer e) {
        throw new UnsupportedOperationException("immuteable list!");
    }

    @Override
    public boolean remove(Object o) {
        throw new UnsupportedOperationException("immuteable list!");
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        for (Object cc : c) {
            if (!contains(cc)) {
                return false;
            }
        }

        return true;
    }

    @Override
    public boolean addAll(Collection<? extends Integer> c) {
        throw new UnsupportedOperationException("immuteable list!");
    }

    @Override
    public boolean addAll(int index, Collection<? extends Integer> c) {
        throw new UnsupportedOperationException("immuteable list!");
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        throw new UnsupportedOperationException("immuteable list!");
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        throw new UnsupportedOperationException("immuteable list!");
    }

    @Override
    public void clear() {
        throw new UnsupportedOperationException("immuteable list!");
    }

    @Override
    public Integer get(int index) {
        if (index >= size()) {
            throw new IndexOutOfBoundsException("" + index + " is out of bounds: [0," + (size() - 1) + "]");
        }

        return start + steps * index;
    }

    @Override
    public Integer set(int index, Integer element) {
        throw new UnsupportedOperationException("immuteable list!");
    }

    @Override
    public void add(int index, Integer element) {
        throw new UnsupportedOperationException("immuteable list!");
    }

    @Override
    public Integer remove(int index) {
        throw new UnsupportedOperationException("immuteable list!");
    }

    @Override
    public int indexOf(Object o) {
        if (!contains(o)) {
            return -1;
        }
        Integer i = (Integer) o;
        return (int) Math.floor(((double) i - start) / (double) steps);
    }

    @Override
    public int lastIndexOf(Object o) {
        return indexOf(o);
    }

    @Override
    public ListIterator<Integer> listIterator() {
        return listIterator(0);
    }

    @Override
    public ListIterator<Integer> listIterator(final int index) {
        return new ListIterator<Integer>() {
            int next = start + index * steps;

            @Override
            public boolean hasNext() {
                return next + steps <= end;
            }

            @Override
            public Integer next() {
                int res = next;
                next += steps;
                return res;
            }

            @Override
            public boolean hasPrevious() {
                return next - steps * 2 >= end;
            }

            @Override
            public Integer previous() {
                int res = next - steps;
                next -= steps;
                return res;
            }

            @Override
            public int nextIndex() {
                return indexOf(next);
            }

            @Override
            public int previousIndex() {
                return indexOf(next - steps * 2);
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException("immuteable list!");
            }

            @Override
            public void set(Integer e) {
                throw new UnsupportedOperationException("immuteable list!");
            }

            @Override
            public void add(Integer e) {
                throw new UnsupportedOperationException("immuteable list!");
            }
        };
    }

    @Override
    public List<Integer> subList(int fromIndex, int toIndex) {
        return new RangeOfNumbersList(get(fromIndex), get(toIndex) - steps, steps);
    }
}
